<?xml version='1.0'?><!DOCTYPE html PUBLIC><html xmlns='http://www.w3.org/1999/xhtml'>
  <head>
    <title>jMock - Writing Custom Invocation Matchers</title>
    <link href='/jmock.css' title='Navigation View' rel='stylesheet' type='text/css' media='screen' />
    <link href='/print.css' title='Print Preview' rel='alternate stylesheet' type='text/css' media='screen' />
    <link href='/print.css' rel='stylesheet' type='text/css' media='print' />
    <meta content='' http-equiv='Content-Type' />
  </head>

  <body>
    <div id='banner'>
      <a href='/index.html'><img src='/logo.gif' id='logo' alt='jMock' /></a>
    </div>

    

    
      <div class='Content2Column' id='center'>
        <div id='content'>
          <h1 class='FirstChild'>Writing Custom Invocation Matchers</h1><p>Invocation matchers control how a mock object matches and verifies
incoming invocations against expectations and stubbed behaviour. The jMock
API is a convenient syntactic sugar for specifying how matchers are added to
a mock object. Sometimes the convenient API does not allow you to specify
matching rules precisely or flexibly enough. In these cases you will need to
write your own invocation matcher classes. This article will show you how to
do just that.</p><p>A mock object contains a list of expectations (and stubs, but we can
consider a stub to be a degerate form of expectation and jMock uses the same
type of object to implement both). When a mock object receives an invocation
it searches for an expectation to process the invocation, starting with the
most recently specified expectation and working backwards until it finds
match. Each expectation contains matching rules that control which
invocations it matches. An expectation matches an invocation if all of its
matching rules match the invocation. The jMock API provides a concise,
descriptive syntax for adding expectations to a mock and adding matching
rules to expectations.</p><p>An matching rule is an object that implements the
<code><a href='/docs/javadoc/org/jmock/core/InvocationMatcher.html'>InvocationMatcher</a><span class='LinkFootnoteRef'><sup>1</sup></span></code>
interface. It has the following responsiblities:</p><ul>
  <li>report whether it matches against an invocation (the
    <code>matches</code> method).</li>
  <li>check and record information about a dispatched invocation, if required
    (the <code>invoked</code> method).</li>
  <li>verify that expected invocations have actually been received. (the
    <code>verify</code> method from the <a href='/docs/javadoc/org/jmock/core/Verifiable.html'><code>Verifiable</code></a><span class='LinkFootnoteRef'><sup>2</sup></span>
    interface).</li>
  <li>provide a readable description to be included in test failure messages
    (the <code>describeTo</code> method from the <a href='/docs/javadoc/org/jmock/core/SelfDescribing.html'><code>SelfDescribing</code></a><span class='LinkFootnoteRef'><sup>3</sup></span>
    interface).</li>
  <li>report if its description is not an empty string (the
    <code>hasDescription</code> method).</li>
</ul><p>In most cases, you will want to define a new matching rule that does
change state when an invocation occurs. Also, you should always provide a
description for your matching rule, so the <code>hasDescription</code> method
should always return <code>true</code>. This common behaviour is already
implemented in the abstract <a href='/docs/javadoc/org/jmock/core/matcher/StatelessInvocationMatcher.html'><code>StatelessInvocationMatcher</code></a><span class='LinkFootnoteRef'><sup>4</sup></span>
class. You can therefore define a new matching rule by extending
<code>StatelessInvocationMatcher</code> and defining the <code>matches</code>
and <code>describeTo</code> methods.</p><h2>An Example Custom Matcher</h2><p>Suppose we want to stub all Java Bean property getters to return some
default results. Returning default results is performed by a <a href='/docs/javadoc/org/jmock/core/stub/DefaultResultStub.html'><code>DefaultResultStub</code></a><span class='LinkFootnoteRef'><sup>5</sup></span>.
But how do we match property getter methods? We need to write a custom
<code>InvocationMatcher</code> that only matches invocations of bean property
getter methods. Here's what a test will look like that uses such a custom
matcher:</p><div class='Source Java'>
<pre>InvocationMatcher beanPropertyGetters = new BeanPropertyGetterMatcher();
DefaultResultStub returnDefaultValue = new DefaultResultStub();
Mock mock = ...

public void testListChildren() {
    ...
    mockPerson.stubs().match(beanPropertyGetters).will(returnDefaultValue);
    ...
}</pre>
</div><p>We can write the <code>BeanPropertyGetterMatcher</code> class by extending
<code>StatelessInvocationMatcher</code>:</p><div class='Source Java'>
<pre>public class BeanPropertyGetterMatcher extends StatelessInvocationMatcher {
   ...
}</pre>
</div><p>We now need to write the <code>matches</code> method to return whether the
invocation is the getter method of a Java Bean property, using the Java Beans
API. The method will use Bean introspection to list the property descriptors
of the class that defines the invoked method. It then searches the list of
property descriptors for a descriptor with a getter method that is the same
as the invoked method.</p><div class='Source Java'>
<pre>public boolean matches(Invocation invocation) {
    Class beanClass = invocation.invokedMethod.getDeclaringClass();

    try {
        BeanInfo beanInfo = Introspector.getBeanInfo(beanClass);
        PropertyDescriptor[] properties = beanInfo.getPropertyDescriptors();

        for( int i = 0; i &lt; properties.length; i++ ) {
            if( invocation.invokedMethod.equals( properties[i].getReadMethod() ) ) return true;
        }
        return false;
    }
    catch( IntrospectionException ex ) {
        throw new AssertionFailedError("could not introspect bean class" + beanClass + ": " + ex.getMessage() );
    }
}</pre>
</div><p>Finally we must write the <code>describeTo</code> method to generate a
description of what our new class matches. The description will be included
in the description of any expectation that uses the matcher, which itself
will be included in error messages when tests fail. Our new class matches any
bean property getter, so that's what our description will be:</p><div class='Source Java'>
<pre>public StringBuffer describeTo(StringBuffer buffer) {
    return buffer.append("any bean property getter");
}</pre>
</div><p>The entire matcher class is shown below:</p><div class='Source Java'>
<pre>public class BeanPropertyGetterMatcher extends StatelessInvocationMatcher {

    public boolean matches(Invocation invocation) {
        Class beanClass = invocation.invokedMethod.getDeclaringClass();

        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(beanClass);
            PropertyDescriptor[] properties = beanInfo.getPropertyDescriptors();

            for( int i = 0; i &lt; properties.length; i++ ) {
                if( invocation.invokedMethod.equals( properties[i].getReadMethod() ) ) return true;
            }
            return false;
        }
        catch( IntrospectionException ex ) {
            throw new AssertionFailedError("could not introspect bean class" + beanClass + ": " + ex.getMessage() );
        }
    }

    public StringBuffer describeTo(StringBuffer buffer) {
        return buffer.append("any bean property getter");
    }
}</pre>
</div>
        <div class='LinkFootnotes'><p class='LinkFootnotesHeader'>Links:</p><p>1. <a href='http://www.jmock.org/docs/javadoc/org/jmock/core/InvocationMatcher.html'>http://www.jmock.org/docs/javadoc/org/jmock/core/InvocationMatcher.html</a></p><p>2. <a href='http://www.jmock.org/docs/javadoc/org/jmock/core/Verifiable.html'>http://www.jmock.org/docs/javadoc/org/jmock/core/Verifiable.html</a></p><p>3. <a href='http://www.jmock.org/docs/javadoc/org/jmock/core/SelfDescribing.html'>http://www.jmock.org/docs/javadoc/org/jmock/core/SelfDescribing.html</a></p><p>4. <a href='http://www.jmock.org/docs/javadoc/org/jmock/core/matcher/StatelessInvocationMatcher.html'>http://www.jmock.org/docs/javadoc/org/jmock/core/matcher/StatelessInvocationMatcher.html</a></p><p>5. <a href='http://www.jmock.org/docs/javadoc/org/jmock/core/stub/DefaultResultStub.html'>http://www.jmock.org/docs/javadoc/org/jmock/core/stub/DefaultResultStub.html</a></p></div></div>
	    <div class='Meta'>
	      <p><a href='http://cvs.jmock.codehaus.org/jmock/website/content/custom-matchers.html'>Document History</a></p>
	    </div>
      </div>
    

    <div class='SidePanel' id='left'>
      <div class='MenuGroup'>
        <h1><a href='/download.html'>Software</a></h1>
        <ul>
          <li><a href='/download.html'>Download</a></li>
          <li><a href='/repository.html'>Anonymous CVS Access</a></li>
          <li><a href='/license.html'>Project License</a></li>
          <li><a href='/CHANGELOG'>Change Log</a></li>
        </ul>
      </div>

      <div class='MenuGroup'>
        <h1><a href='/docs.html'>Documentation...</a></h1>
        <ul>
          <li><a href='/getting-started.html'>Getting Started</a></li>
          <!-- <li><a href="">Frequently Asked Questions</a></li> -->
          <li><a href='/docs/javadoc/index.html' target='jmock-javadoc'>JavaDocs</a></li>
          <li><a href='http://www.mockobjects.com'>More about Mock Objects</a></li>
        </ul>
      </div>

      <div class='MenuGroup'>
        <h1>User Support</h1>
        <ul>
          <li><a href='/mailing-lists.html'>Mailing Lists</a></li>
          <li><a href='http://jira.codehaus.org/secure/BrowseProject.jspa?id=10336'>Issue Tracker</a></li>
          <li><a href='/news-rss2.xml'>News Feed (RSS 2.0)</a></li>
        </ul>
      </div>

      <div class='MenuGroup'>
        <h1><a href='/development.html'>Development...</a></h1>
        <ul>
          <li><a href='/how-to-contribute.html'>How to Contribute</a></li>
          <li><a href='/team.html'>Development Team</a></li>
        </ul>
      </div>

      <div class='MenuGroup'>
        <h1>Related Sites</h1>
        <ul>
          <li><a href='http://www.mockobjects.com'>Mock Objects</a></li>
          <li><a href='http://www.junit.org'>JUnit</a></li>
          <li><a href='http://www.nmock.org'>nMock</a></li>
          <li><a href='http://www.codehaus.org'>Project hosted by Codehaus</a></li>
        </ul>
      </div>
    </div>

    
  </body>
</html>